<template>
  <el-form
    ref="formRef"
    :model="formData"
    :rules="computedRules"
    :label-width="labelWidth"
    :size="size"
    :disabled="disabled"
    @submit.prevent
  >
    <el-row :gutter="gutter">
      <template v-for="item in visibleFormConfig" :key="item.key">
        <el-col v-bind="getColProps(item)">
          <el-form-item
            :label="item.name + ':'"
            :prop="item.key"
            :required="item.required"
            :label-width="item.labelWidth || props.labelWidth"
          >
            <DynamicFormItem
              :config="item"
              :model-value="formData[item.key]"
              @update:model-value="updateFormData(item.key, $event)"
            />
          </el-form-item>
        </el-col>
      </template>

      <!-- 按钮区域跟在表单项后面 -->
      <el-col
        v-if="showButtons"
        :span="type === 'search' ? 4 : 24"
        class="form-buttons-col"
      >
        <div
          class="form-buttons"
          :class="{ 'form-buttons-left': type === 'search' }"
        >
          <template v-if="type === 'submit'">
            <el-button @click="handleCancel">取消</el-button>
            <el-button type="primary" @click="handleSubmit">确认</el-button>
          </template>
          <template v-else>
            <el-button @click="handleReset">重置</el-button>
            <el-button type="primary" @click="handleSearch">搜索</el-button>
          </template>
        </div>
      </el-col>
    </el-row>
  </el-form>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from "vue";
import DynamicFormItem from "./DynamicFormItem.vue";
import type {
  DynamicFormProps,
  DynamicFormInstance,
  FormItemConfig,
} from "./types";

defineOptions({
  name: "DynamicForm",
});

const props = withDefaults(defineProps<DynamicFormProps>(), {
  labelWidth: "100px",
  gutter: 20,
  size: "default",
  disabled: false,
  type: "search",
  showButtons: true,
});

const emit = defineEmits<{
  "update:modelValue": [value: Record<string, any>];
  search: [value: Record<string, any>];
  reset: [];
  submit: [value: Record<string, any>];
  cancel: [];
}>();

const formRef = ref();
const formData = ref<Record<string, any>>({});

// 初始化表单数据
const initFormData = () => {
  const data: Record<string, any> = {};
  props.formConfig.forEach((item) => {
    data[item.key] =
      props.modelValue[item.key] ??
      item.defaultValue ??
      getDefaultValue(item.type, item.params);
  });
  formData.value = data;
};

// 获取默认值
const getDefaultValue = (type: string, params?: any) => {
  // 如果是 date 类型且 params.type 为 daterange，返回空数组
  if (type === "date" && params?.type === "daterange") {
    return [];
  }

  switch (type) {
    case "checkbox":
      return [];
    case "switch":
      return false;

    case "number":
    case "slider":
    case "rate":
      return 0;
    case "select":
      return null; // select使用null作为默认值，避免空字符串导致验证问题
    default:
      return "";
  }
};

// 计算可见的表单配置
const visibleFormConfig = computed(() => {
  return props.formConfig.filter((item) => {
    if (item.show === undefined) return true;
    if (typeof item.show === "boolean") return item.show;
    if (typeof item.show === "function") return item.show(formData.value);
    return true;
  });
});

// 计算表单验证规则
const computedRules = computed(() => {
  const rules: Record<string, any[]> = {};

  // 合并props传入的rules
  if (props.rules) {
    Object.assign(rules, props.rules);
  }

  // 根据配置生成规则
  props.formConfig.forEach((item) => {
    const itemRules: any[] = [];

    // 必填验证
    if (item.required) {
      // 根据不同类型设置不同的验证消息和触发时机
      const getMessage = (type: string, name: string) => {
        switch (type) {
          case "select":
          case "radio":
          case "checkbox":
          case "cascader":
            return `请选择${name}`;
          case "upload":
            return `请上传${name}`;
          case "date":
          case "datetime":
          case "time":
            return `请选择${name}`;
          default:
            return `请输入${name}`;
        }
      };

      // select类型只在blur时触发验证，避免初始化时触发
      const getTrigger = (type: string) => {
        switch (type) {
          case "select":
          case "cascader":
            return ["blur"]; // 只在失去焦点时触发，避免初始化时触发
          default:
            return ["blur", "change"];
        }
      };

      itemRules.push({
        required: true,
        message: getMessage(item.type, item.name),
        trigger: getTrigger(item.type),
      });
    }

    // 自定义规则
    if (item.rules) {
      itemRules.push(...item.rules);
    }

    if (itemRules.length > 0) {
      rules[item.key] = itemRules;
    }
  });

  return rules;
});

// 获取栅格布局属性
const getColProps = (item: FormItemConfig) => {
  // 如果是 submit 类型，使用竖向布局（每行占满）
  if (props.type === "submit") {
    return {
      span: 24,
      ...item.col,
    };
  }

  // 如果是 search 类型，使用更小的默认 span
  if (props.type === "search") {
    return {
      span: 4,
      ...item.col,
    };
  }

  // 默认横向布局
  const result = {
    xs: item.col?.xs ?? 24,
    sm: item.col?.sm ?? 12,
    md: item.col?.md ?? 12,
    lg: item.col?.lg ?? 8,
    xl: item.col?.xl ?? 8,
    span: item.col?.span,
    ...item.col,
  };

  return result;
};

// 更新表单数据
const updateFormData = (key: string, value: any) => {
  formData.value[key] = value;
  emit("update:modelValue", { ...formData.value });
};

// 监听外部数据变化
watch(
  () => props.modelValue,
  (newVal) => {
    // 直接更新整个 formData，确保所有字段都能响应式更新
    formData.value = { ...newVal };

    // 清除可能的验证错误
    setTimeout(() => {
      clearValidate();
    }, 0);
  },
  { deep: true, immediate: true }
);

// 监听配置变化，重新初始化数据
watch(
  () => props.formConfig,
  () => {
    initFormData();
    // 配置变化后也清除验证状态
    setTimeout(() => {
      clearValidate();
    }, 0);
  },
  { deep: true }
);

// 表单方法
const validate = (): Promise<boolean> => {
  return new Promise((resolve) => {
    formRef.value?.validate((valid: boolean) => {
      resolve(valid);
    });
  });
};

const resetFields = async () => {
  // 重置 Element Plus 表单的验证状态和 DOM
  formRef.value?.resetFields();

  // 重置表单数据到默认值，而不是从 props.modelValue 恢复
  const data: Record<string, any> = {};
  props.formConfig.forEach((item) => {
    data[item.key] =
      item.defaultValue ?? getDefaultValue(item.type, item.params);
  });
  formData.value = data;

  // 等待 DOM 更新后，再同步更新到父组件
  await nextTick();
  emit("update:modelValue", { ...formData.value });
};

const clearValidate = () => {
  formRef.value?.clearValidate();
};

const validateField = (prop: string): Promise<boolean> => {
  return new Promise((resolve) => {
    formRef.value?.validateField(prop, (valid: boolean) => {
      resolve(valid);
    });
  });
};

// 按钮处理方法
const handleSearch = () => {
  emit("search", formData.value);
};

const handleReset = () => {
  resetFields();
  emit("reset");
};

const handleSubmit = async () => {
  const valid = await formRef.value?.validate();
  if (valid) {
    emit("submit", formData.value);
  }
};

const handleCancel = () => {
  emit("cancel");
};

// 暴露方法给父组件
defineExpose<DynamicFormInstance>({
  validate,
  resetFields,
  clearValidate,
  validateField,
});

onMounted(() => {
  initFormData();
  // 初始化完成后清除验证状态，避免初始化时的验证错误
  setTimeout(() => {
    clearValidate();
  }, 0);
});
</script>

<style scoped>
.form-buttons {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  /* margin-top: 24px; */
  /* padding-top: 16px; */
  /* border-top: 1px solid var(--el-border-color-lighter); */
}

.form-buttons-left {
  justify-content: center;
}

.form-buttons-col {
  display: flex;
  align-items: flex-start;
  margin-left: 8px;
  /* justify-content: center; */
}
</style>
